﻿namespace StockSharp.Algo.Indicators.Trend
{
    using System.ComponentModel;
    using System.Linq;
using System;

    /// <summary>
    /// Скользящая средняя Халла (Hull Moving Average).
    /// </summary>
    [DisplayName("HMA")]
    [Description("Hull Moving Average.")]
    public class HullMovingAverage : LengthIndicator<decimal>
    {
        private WeightedMovingAverage _wmaSlow = new WeightedMovingAverage();
        private WeightedMovingAverage _wmaFast = new WeightedMovingAverage();
        private WeightedMovingAverage _wmaResult = new WeightedMovingAverage();

        private int _intSqrtPeriod;
        
        /// <summary>
		/// Создать <see cref="HullMovingAverage"/>.
		/// </summary>
		public HullMovingAverage()
			: base(typeof(decimal))
		{
            Length = 10;
            SqrtPeriod = 0;
		}

        /// <summary>
		/// Длина периода. По-умолчанию длина равна 10.
		/// </summary>
		public override int Length
		{
			get { return base.Length; }
			set
			{
				_wmaSlow.Length = value;
                _wmaFast.Length = (int)(value / 2);

                if (0 == SqrtPeriod)
                {
                    _wmaResult.Length = (int)(Math.Sqrt(value));
                }
                else
                {
                    _wmaResult.Length = SqrtPeriod;
                }
                base.Length = value;
			}
		}

        /// <summary>
        /// Период результирующей средней. Если SqrtPerio равен 0, период результирующей средней равен квадратному корню периода HMA. Значение SqrtPeriod по умолчанию - 0. 
        /// </summary>
        public int SqrtPeriod
        {
            get
            {
                return _intSqrtPeriod;
            }
            set
            {
                _intSqrtPeriod = value;

                if (0 == value)
                {
                    _wmaResult.Length = (int)(Math.Sqrt(this.Length));
                }
                else
                {
                    _wmaResult.Length = value;
                }
            }
        }

        /// <summary>
        /// Сформирован ли индикатор.
        /// </summary>
        public override bool IsFormed
        {
            get { 
            
                
                return _wmaResult.IsFormed; 
            
            }
        }

        /// <summary>
		/// Сбросить состояние индикатора на первоначальное. Метод вызывается каждый раз, когда меняются первоначальные настройки (например, длина периода).
		/// </summary>
		public override void Reset()
		{
			base.Reset();

            _wmaSlow.Reset();
            _wmaFast.Reset();
            _wmaResult.Reset();
        }

		/// <summary>
		/// Обработать входное значение.
		/// </summary>
		/// <param name="input">Входное значение.</param>
		/// <returns>Результирующее значение.</returns>
		protected override decimal OnProcess(IIndicatorValue input)
		{
            _wmaSlow.Process(input);
            _wmaFast.Process(input);

            if (_wmaFast.IsFormed && _wmaSlow.IsFormed)
            {

                var diff = 2 * _wmaFast.GetCurrentValue<decimal>() - _wmaSlow.GetCurrentValue<decimal>();

                _wmaResult.Process(diff);
            }

            return _wmaResult.GetCurrentValue<decimal>();
		}
	}

}
